package com.example.bidding.service;

import com.alibaba.fastjson.JSON;
import com.example.bidding.feign.MessageFeign;
import com.example.bidding.feign.UserFeign;
import com.example.bidding.mapper.*;
import com.example.common.Ov.UserOv;
import com.example.common.entity.PageParam;
import com.example.common.entity.ResponseCode;
import com.example.common.entity.Rsp;
import com.example.common.pojo.*;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;

/**
 * @author 小许
 * @Title:
 * @Package
 * @Description:
 * @date 2020/11/23-19:12
 */
@Service
public class LoanService {
    @Autowired
    private LoanMapper loanMapper;
    @Autowired
    private BorrowMapper borrowMapper;
    @Autowired
    RedisServiceImpl redisService;
    @Autowired
    private MessageFeign messageFeign;
    @Autowired
    private UserFeign userFeign;
    @Autowired
    private RepayRecordMapper repayRecordMapper;
    @Autowired
    private ReprofitRecordMapper reprofitRecordMapper;
    @Autowired
    private TransCodeMapper transCodeMapper;

    /**
     * 查询该标已出借信息
     *
     * @param id
     * @param pageParam
     * @return
     */
    public Rsp getLoanByBorrowId(String id, PageParam pageParam) {
        PageHelper.startPage(pageParam.getPageNo(), pageParam.getPageSize());
        List<Loan> loanList = loanMapper.getLoanByBorrowId(id);
        PageInfo<Loan> pageInfo = new PageInfo<>(loanList);
        if (StringUtils.isEmpty(pageInfo)) {
            return new Rsp(ResponseCode.ERROR, "访问失败");
        }
        return new Rsp(ResponseCode.SUCCESS, pageInfo, "访问成功");
    }

    //查询该标已付款的出借信息
    public List<Loan> getPaiedLoanByBorrowId(Integer borrowId) {
        return loanMapper.getLoanByBorrowIdAndPaied(borrowId);
    }

    //获取投标的信息
    public Rsp getLoanMoney(UserOv userOv) {
        //通过用户的id来查找投标
        List<Loan> loans = loanMapper.getLoanByUserId(userOv.getId());
        BigDecimal totalMoney = new BigDecimal(0);
        if (StringUtils.isEmpty(loans)) {
            return new Rsp(1, totalMoney, "此人没有投标记录");
        } else {
            for (Loan loan : loans) {
                BigDecimal loanMoney = loan.getLoanMoney();
                totalMoney = totalMoney.add(loanMoney);
            }
            return new Rsp(0, totalMoney, "请求成功");
        }
    }


    /**
     * 秒杀
     */
    @Transactional
    public Rsp addLoan(Loan loan) throws InterruptedException {
        //生成锁的过期时间：当前时间+你任务处理完一个下单任务需要花费的时间（1秒） 和 锁的key：库存的id
        long expireTime = System.currentTimeMillis() + 5000;
        String stockKey = "loan:secKill:" + loan.getBorrowId();
        //重复下单判断
        if (!StringUtils.isEmpty(loanMapper.selectByNo(loan.getNo()))) {
            return new Rsp(ResponseCode.ERROR, "请勿重复下单");
        }
        //调用枷锁方法
        if (!redisService.lock(stockKey, expireTime + "")) {
            return new Rsp(ResponseCode.ERROR, "手慢了 没抢到。。。。");
        }
        //查询商品
        Borrow borrow = borrowMapper.selectByPrimaryKey(loan.getBorrowId());
        //已借出金额
        BigDecimal borrowedMoney = borrow.getBorrowedMoney();
        //借款总金额大于已借出金额,有库存
        if (borrow.getBorrowMoney().compareTo(borrowedMoney) == 1) {
            //出借金额大于库存需入借金额，库存不够
            if (loan.getLoanMoney().compareTo(borrow.getBorrowMoney().subtract(borrowedMoney)) == 1) {
                return new Rsp(ResponseCode.ERROR, "借款失败,剩余筹建金额:" + borrow.getBorrowMoney().subtract(borrowedMoney));
            }
            //修改库存
            borrow.setBorrowedMoney(borrowedMoney.add(loan.getLoanMoney()));
            borrow.setBorrowNum(borrow.getBorrowNum() + 1);
            //
            int res = borrowMapper.updateByPrimaryKeySelective(borrow);
            //添加订单(loan)
            //         利息   =  (借出金额                *                利率)                         /     (期数/12)
            double termProfit = loan.getLoanMoney().doubleValue() * Double.parseDouble(borrow.getBorrowRate()) / 100 / 12;
            loan.setProfit(new BigDecimal(termProfit * Integer.parseInt(borrow.getBorrowTerm())));
            loan.setAnnualProfit(termProfit * 12 + "");
            loan.setRetrieveMoney(new BigDecimal("0.00"));
            loan.setTotal(loan.getLoanMoney().add(loan.getProfit()));
            loan.setCreateTime(new Date());

//            int rannum = (int) (new Random().nextDouble() * (99999 - 10000 + 1)) + 10000;// 获取5位随机数
            loan.setNo(loan.getNo());

            int id = loanMapper.insert(loan);
            loan.setBorrow(borrow);
            loan.setUser(new User());
            if (id == 0) {
                new Rsp(ResponseCode.ERROR, "下单失败,待会再试试吧");
            }
            //向消息队列发送消息,设置订单有效时间
            messageFeign.sendMessage(loan.getNo());

            boolean isSuccess = res == 1;
//            解锁
            redisService.unlock(stockKey, expireTime + "");
            if (isSuccess) {
                System.out.println("下单成功");
            }

            return isSuccess ? new Rsp(ResponseCode.SUCCESS, loan, "下单成功") : new Rsp(ResponseCode.ERROR, "下单失败");
        } else {
            redisService.unlock(stockKey, expireTime + "");
            if (borrow.getIsOverComplete() == 100) {

            }
            return new Rsp(ResponseCode.ERROR, "已全部借出，下次再试试");
        }
    }

    /**
     * 超时关闭订单
     *
     * @param orderNo
     */
    @Transactional
    public void closeLoan(String orderNo) {
        Loan loan = loanMapper.selectByNo(orderNo);
        if (!StringUtils.isEmpty(loan)) {
            if (loan.getStatus() == 0) {
                //修改loan（订单）支付状态
                loan.setStatus(3);
                loanMapper.updateByPrimaryKey(loan);
                //修改borrow（库存）剩余金额以及借款人数
                Borrow borrow = borrowMapper.selectByPrimaryKey(loan.getBorrowId());
                borrow.setBorrowNum(borrow.getBorrowNum() - 1);
                borrow.setBorrowedMoney(borrow.getBorrowedMoney().subtract(loan.getLoanMoney()));
                borrowMapper.updateByPrimaryKeySelective(borrow);

                TransCode transCode = new TransCode();
                transCode.setUserId(loan.getUserId());
                transCode.setType("付款");
                transCode.setContent("你有一笔订单"+orderNo+"超时未支付，已关闭");
                transCodeMapper.insertSelective(transCode);
            }
        }
    }

    /**
     * 余额支付
     *
     * @param userOv
     * @param loan
     * @return
     */
    @Transactional
    public Rsp pay(UserOv userOv, Loan loan) {
        //获取标信息
        Borrow borrow = borrowMapper.selectByPrimaryKey(loan.getBorrowId());
        //当前时间大于招标结束时间
        if (new Date().getTime() > borrow.getBorrowEndTime().getTime()) {
            //设置标状态为已流标
            borrow.setStatus(4);
            //流标之后将已支付的用户退款
            userFeign.refund(borrow.getId());

            //发一条通知
            TransCode transCode = new TransCode();
            transCode.setUserId(borrow.getUserId());
            transCode.setType("流标");
            transCode.setContent("您的借款"+borrow.getBorrowTitle()+"未筹集完成，已流标");
            transCodeMapper.insertSelective(transCode);


            //获取已支付的loan
            List<Loan> loanList = loanMapper.getLoanByBorrowIdAndPaied(borrow.getId());
            for (Loan l : loanList) {
                //修改loan的状态为流标已退款
                l.setStatus(4);
                loanMapper.updateByNoSelective(l);
            }
            return new Rsp(ResponseCode.ERROR, "招标时间已过");
        }
        //订单已关闭
        if (loanMapper.selectByNo(loan.getNo()).getStatus() == 3) {
            return new Rsp(ResponseCode.ERROR, "订单超时未支付已关闭");
        }
        //获取当前登录用户支付密码
        User user = new User();
        user.setId(userOv.getId());
        Rsp rsp = userFeign.getUserInfoById(user);
        User user1 = JSON.parseObject(JSON.toJSONString(rsp.getResult()), User.class);
        //支付密码正确
        if (user1.getPayPassword().equals(loan.getUser().getPayPassword())) {
            //判断账户余额是否足够
            if (user1.getBalance().compareTo(loan.getLoanMoney()) == 1 ||
                    user1.getBalance().compareTo(loan.getLoanMoney()) == 0) {
                //支付完成，支付方式为余额
                loan.setStatus(1);
                loan.setType(0);
                loanMapper.updateByNoSelective(loan);
                userFeign.subBalance(user1, loan.getLoanMoney());
                //判断是否满标且生成详情
                isFullBid(loan, borrow);

            } else {
                return new Rsp(ResponseCode.ERROR, "余额不足，请先充值");
            }
        } else {
            return new Rsp(ResponseCode.ERROR, "支付密码错误");
        }
        return new Rsp(ResponseCode.SUCCESS, "支付成功");
    }

    //判断是否满标且生成详情
    public void isFullBid(Loan loan, Borrow borrow) {
        //获取已支付的loan
        List<Loan> loanList = loanMapper.getLoanByBorrowIdAndPaied(loan.getBorrowId());
        BigDecimal total = new BigDecimal(0);
        for (Loan l : loanList) {
            total = total.add(l.getLoanMoney());
        }
        //计算完成百分比
        int isOverComplete = (int) (total.doubleValue() / borrow.getBorrowMoney().doubleValue() * 100);
        borrow.setIsOverComplete(borrow.getIsOverComplete() + isOverComplete);

        //已满标
        if (borrow.getBorrowMoney().compareTo(total) == 0) {
            userFeign.addBalance(borrow.getUserId(),borrow.getBorrowMoney());
            //设置状态为满标
            borrow.setStatus(2);
            borrow.setBorrowFullTime(new Date());
            borrow.setIsOverComplete(100);
            borrow.setRepaymentDate(getTime(Integer.parseInt(borrow.getBorrowTerm())));

            //总的利率
            double rate = Double.parseDouble(borrow.getBorrowRate()) / 100;

            double realRate1 = Integer.parseInt(borrow.getBorrowTerm());
            double realRate = realRate1 / 12;
            ArrayList<ReprofitRecord> reprofitRecords = new ArrayList<>();
            //总利息
            double totalProfit1 = borrow.getBorrowMoney().doubleValue() * rate * realRate;

            BigDecimal totalProfit = new BigDecimal(totalProfit1);
            //每期利息
            BigDecimal termProfit = borrow.getBorrowMoney().multiply(new BigDecimal(borrow.getBorrowRate())).divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP).divide(new BigDecimal(12), 2, BigDecimal.ROUND_HALF_UP);
            //每期本金
            BigDecimal termMoney = borrow.getBorrowMoney().divide(new BigDecimal(borrow.getBorrowTerm()), 2, BigDecimal.ROUND_HALF_UP);
            //生成loan详情和待还详情
            for (int i = 0; i < Integer.parseInt(borrow.getBorrowTerm()); i++) {
                RepayRecord repayRecord = new RepayRecord();
                //borrowId
                repayRecord.setBorrowId(borrow.getId());
                //第几期
                repayRecord.setPeriodsNum(i + 1);
                //解决精度丢失问题,最后一次遍历
                if (i + 1 == Integer.parseInt(borrow.getBorrowTerm())) {
                    //  总金额或总利息-（每期金额或利息）*之前的期数
                    repayRecord.setRepayInterest(totalProfit.subtract(termProfit.multiply(new BigDecimal(i))));
                    repayRecord.setRepayMoney(borrow.getBorrowMoney().subtract(termMoney.multiply(new BigDecimal(i))).add(repayRecord.getRepayInterest()));
                } else {
                    //利息
                    repayRecord.setRepayInterest(termProfit);
                    //本金
                    repayRecord.setRepayMoney(termMoney.add(repayRecord.getRepayInterest()));
                }
                //还款日期
                repayRecord.setRepayTime(getTime(i + 1));
                repayRecordMapper.insertSelective(repayRecord);

                for (Loan l : loanList) {
                    ReprofitRecord reprofitRecord = new ReprofitRecord();
                    BigDecimal reprofitTermProfit = l.getProfit().divide(new BigDecimal(borrow.getBorrowTerm()), 2, BigDecimal.ROUND_HALF_UP);
                    BigDecimal reprofitTermMoney = l.getLoanMoney().divide(new BigDecimal(borrow.getBorrowTerm()), 2, BigDecimal.ROUND_HALF_UP);
                    //设置loanId
                    reprofitRecord.setLoanId(l.getId());
                    //设置待收款Id
                    reprofitRecord.setRepayRecordId(repayRecord.getId());
                if (i + 1 == Integer.parseInt(borrow.getBorrowTerm())) {
                    //设置待收利息
                    reprofitRecord.setReprofitInterest(l.getProfit().subtract(reprofitTermProfit.multiply(new BigDecimal(i))));
                    //设置待收本金
                    reprofitRecord.setReprofitMoney(l.getLoanMoney().subtract(reprofitTermMoney.multiply(new BigDecimal(i))));
                } else {
                    //设置待收利息
                    reprofitRecord.setReprofitInterest(l.getProfit().divide(new BigDecimal(borrow.getBorrowTerm()), 2, BigDecimal.ROUND_HALF_UP));
                    //设置待收本金
                    reprofitRecord.setReprofitMoney(l.getLoanMoney().divide(new BigDecimal(borrow.getBorrowTerm()), 2, BigDecimal.ROUND_HALF_UP));
                }
                    //设置应收日期
                    reprofitRecord.setReprofitTime(getTime(i));
                    reprofitRecords.add(reprofitRecord);
                }
            }
            reprofitRecordMapper.insertSelectiveBatch(reprofitRecords);
        }
        borrowMapper.updateByPrimaryKeySelective(borrow);

        //发一条通知
        TransCode transCode = new TransCode();
        transCode.setUserId(borrow.getUserId());
        transCode.setType("满标");
        transCode.setContent("您的筹借款"+borrow.getBorrowTitle()+"筹集完成，稍后自动到账，请按时还款");
        transCodeMapper.insertSelective(transCode);
    }

    //还款日期计算
    public Date getTime(Integer i) {
        Calendar cal = Calendar.getInstance();//获取一个Calendar对象
        cal.setTime(new Date());
        cal.add(Calendar.MONTH, i);//获取当前时间的下i个月
        return cal.getTime();
    }

    public Rsp getProfitInfo(UserOv userOv) {
        List<ReprofitRecord> reprofitRecords = reprofitRecordMapper.selectByUserId(userOv.getId());
        HashMap<String, Object> map = new HashMap<>();
        //待收益
        List<ReprofitRecord> reprofit = new ArrayList<>();
        //带收益本金
        BigDecimal reprofitMoney = new BigDecimal(0);
        //待收益利息
        BigDecimal reprofitInterest = new BigDecimal(0);
        //已收益
        List<ReprofitRecord> profited = new ArrayList<>();
        //已收益本金
        BigDecimal profitedMoney = new BigDecimal(0);
        //已收益利润
        BigDecimal profitedInterest = new BigDecimal(0);
        for (ReprofitRecord reprofitRecord : reprofitRecords) {
            if (reprofitRecord.getStatus() == 1) {
                profited.add(reprofitRecord);
                profitedMoney = profitedMoney.add(reprofitRecord.getReprofitMoney());
                profitedInterest = profitedInterest.add(reprofitRecord.getReprofitInterest());
            } else {
                reprofit.add(reprofitRecord);
                reprofitMoney = reprofitMoney.add(reprofitRecord.getReprofitMoney());
                reprofitInterest = reprofitInterest.add(reprofitRecord.getReprofitInterest());
            }
        }
        map.put("reprofit", reprofit);
        map.put("profited", profited);
        map.put("profitedMoney", profitedMoney);
        map.put("profitedInterest", profitedInterest);
        map.put("reprofitMoney", reprofitMoney);
        map.put("reprofitInterest", reprofitInterest);
        return new Rsp(ResponseCode.SUCCESS, map, "成功");
    }

    public Rsp getLoanInfo(UserOv userOv, PageParam pageParam) {
        PageHelper.startPage(pageParam.getPageNo(), pageParam.getPageSize());
        List<Loan> loanByUserId = loanMapper.getLoanByUserId(userOv.getId());
        PageInfo<Loan> pageInfo = new PageInfo<>(loanByUserId);
        return new Rsp(ResponseCode.SUCCESS, pageInfo, "成功");
    }
}
